/*
time:20201016 15:37 PM
key:1.本题空节点处理：指向它的指针为空，而不是靠数据来判断为空。
*/
#include <math.h>
#include <iostream>
#include<string>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
using namespace std;

class TreeNode
{
public:
	TreeNode* lc;
	char data;
	TreeNode* rc;
	TreeNode() 
	{
		lc = NULL;
		data = '0';
		rc = NULL;
	}
};

void front_read(TreeNode* head, string& front_middle_str)
{
	if (head != NULL)
	{
	//cout << head->data;
	front_middle_str +=head->data;
	front_read(head->lc, front_middle_str);
	front_read(head->rc, front_middle_str);
	}
}

void middle_read(TreeNode* head, string& front_middle_str)
{
	if (head != NULL)
	{

		middle_read(head->lc, front_middle_str);
		//cout << head->data;
		front_middle_str += head->data;
		middle_read(head->rc, front_middle_str);
	}
}

bool check_same(TreeNode* root1, TreeNode* root2, string& front_middle_str1, string& front_middle_str2)
{
	front_read(root1, front_middle_str1);
	//middle_read(root1, front_middle_str1);

	front_read(root2, front_middle_str2);
	//middle_read(root2, front_middle_str2);
	//cout << front_middle_str1 << endl;
	//cout << front_middle_str2 << endl;
	if (front_middle_str1 == front_middle_str2)
	{
		return 1;
	}
	else
	{
		return 0;
	}
}

int change(string replace)//字符串转整数，不是编号就转成-1。注意不能是字符转整数，编号超过个位数就失效。
{
	if (replace != "-")
	{
		return atoi(replace.c_str());
	}
	else
	{
		return -1;
	}
}

TreeNode* find_target_root(TreeNode** smalltree,  char target, int number_of_roots)//输入树根指针数组，根字符，根个数。
{
	for (int i = 0; i < number_of_roots; i++)
	{
		if (smalltree[i]->data == target)
		{
			return smalltree[i];
		}
	}
}

void creat_tree(TreeNode** smalltree, TreeNode*root, int number_of_roots)
{
	if (root != NULL) 
	{
		for (int i = 0; i < number_of_roots; i++)
		{
			if (root->lc != NULL) 
			{
				if (smalltree[i]->data == root->lc->data)
				{
					root->lc = smalltree[i];
					creat_tree(smalltree, root->lc, number_of_roots);
				}
			}
			if (root->rc != NULL)
			{
				if (smalltree[i]->data == root->rc->data)
				{
					root->rc = smalltree[i];
					creat_tree(smalltree, root->rc, number_of_roots);
				}
			}
		}
	}
}

TreeNode* write_creat_tree()
{
	int n, i;
	string replace;//由于两个number数组都是int较为合理，而输入有掺杂代表空节点的"-"字符串，故需要字符串转整数的媒介。
	cin >> n;
	char* char_name = new char[n];
	int* leftnumber = new int[n];
	int* rightnumber = new int[n];
	//开始输入
	for (i = 0; i < n; i++)
	{
		cin >> char_name[i];

		cin >> replace;
		leftnumber[i] = change(replace);

		cin >> replace;
		rightnumber[i] = change(replace);

	}
	//开始构建每个小单位
	TreeNode** smalltree1 = new TreeNode * [n];
	for (i = 0; i < n; i++)
	{
		smalltree1[i] = new TreeNode;
		smalltree1[i]->data = char_name[i];
		if (leftnumber[i] != -1) //空节点那些就不new了，让他默认NULL
		{
			smalltree1[i]->lc = new TreeNode;
			smalltree1[i]->lc->data = char_name[leftnumber[i]];
		}
		if (rightnumber[i] != -1)
		{
			smalltree1[i]->rc = new TreeNode;
			smalltree1[i]->rc->data = char_name[rightnumber[i]];
		}
	}
	//建一个哈希方便统计
	int* count = new int[int('A') + n];
	for (i = 0; i < int('A') + n; i++)
	{
		count[i] = 0;
	}
	//每单位统计三个字符,注意子树的空指针，前面那些空节点的不new了,空的可读不了里面的date。
	for (i = 0; i < n; i++)
	{
		count[int(smalltree1[i]->data)]++;
		if (smalltree1[i]->lc != NULL)
		{
			count[int(smalltree1[i]->lc->data)]++;
		}
		if (smalltree1[i]->rc != NULL)
		{
			count[int(smalltree1[i]->rc->data)]++;
		}
	}
	//找出只出现过一次的字符，即根对应的字符。
	char char_root1;
	for (i = int('A'); i < int('A') + n; i++)
	{
		if (count[i] == 1)
		{
			char_root1 = char(i);
			//cout << "root1" << char_root1;
			break;
		}
	}
	//通过根字符找到跟指针
	TreeNode* root1 = find_target_root(smalltree1, char_root1, n);
	//从跟指针每递归遍历smalltree数组建立起整棵树
	creat_tree(smalltree1, root1, n);

	return root1;
}

void change_child(TreeNode* root)
{
	TreeNode* place = root->lc;
	root->lc = root->rc;
	root->rc = place;
}

void tg(TreeNode* root1, TreeNode* root2)//同时先序遍历两棵树，但凡有不同则交换。因此最后结果若不同则不是同构。
{
	if (root1 != NULL && root2!= NULL)
	{
		if (root1->lc != NULL && root2->rc != NULL)//两边都不为NULL才能检查数据
		{
			if (root1->lc->data == root2->rc->data)//如果是NULL则无法比较
			{
				change_child(root1);
				tg(root1->lc, root2->lc);
				tg(root1->rc, root2->rc);
			}
		}
		else
		{
			if (root1->lc == NULL || root2->rc == NULL)//有一边是NULL，直接交换。
			{
				change_child(root1);
				tg(root1->lc, root2->lc);
				tg(root1->rc, root2->rc);
			}
			else//两边是NULL，不交换。
			{

			}
		}
	}

}

int main()
{
	//建立树
	TreeNode* root1 = write_creat_tree();
	//front_read(root1);
	TreeNode* root2 = write_creat_tree();
	//front_read(root2);
	//使树1通过左右交换逼近树2
	tg(root1, root2);
	//其实就是两个前序序列字符串
	string front_middle_str1 = "";
	string front_middle_str2 = "";
	//由于这里是左右交换，如果符合的话前序序列就能确定两个是否同构，不需要两个序列组合确认。
	if (check_same(root1, root2, front_middle_str1, front_middle_str2))
	{
		cout<<"Yes";
	}
	else
	{
		cout << "No";
	}

}


